package com.inspectortime.calendar;

import java.util.Calendar;
import java.util.Date;

import com.inspectortime.domain.ScheduleRule;
import com.inspectortime.domain.type.Time;


/**
 * Represents a block of time in a day
 * 
 * @author Owner
 * @version 1.0
 * @created 27-Nov-2007 7:41:13 AM
 */
public class Timeslot implements Comparable {
	

	private boolean available;
	private Time startTime;
	private Time endTime;
	private ScheduleRule originatingRule;
	//private Calendar startCal;
	//private Calendar endCal;
	
	public Timeslot(ScheduleRule rule, Calendar start, Calendar end, boolean available) {
		this.setOriginatingRule(rule);
		if (start != null) {
			this.startTime = new Time(start);	
		}
		if (end != null) {
			this.endTime = new Time(end);	
		}
		this.available = available;
		//this.startCal = new GregorianCalendar(0,0,0, this.startTime.getHour(), this.startTime.getMinute());
		//this.endCal = new GregorianCalendar(0,0,0, this.endTime.getHour(), this.endTime.getMinute());
		
		if (!startTime.before(endTime)) {
			throw new IllegalArgumentException("Start hour/minute must be less than than end hour/minute");
		}
	}
	
	public Timeslot(ScheduleRule rule) {
		this(rule, new Time(rule.getStartHour(), rule.getStartMinute()), new Time(rule.getEndHour(), rule.getEndMinute()), rule.isAvailable());
	}

	public Timeslot(ScheduleRule rule, Time startTime, Time endTime, boolean available) {
		this(rule, startTime.toCalendar(), endTime.toCalendar(), available);
	}
	
	public Timeslot(int startHour, int startMinute,
			int endHour, int endMinute, boolean available) {
		this(null, new Time(startHour, startMinute), new Time(endHour, endMinute), available);		
	}


	/**
	 * @return true if this timeslot represents a time which the inspector is available for appointments
	 */
	public boolean isAvailable() {
		return available;
	}
	
	/**
	 * set true if the timeslot if available for scheduling. False if not
	 * @param available
	 */
	public void setAvailable(boolean available) {
		this.available = available;
	}
	
	/**
	 * @return the starting time of the day for this timeslot
	 */
	public Time getStartTime() {
		return startTime;
	}

	/**
	 * @return the end time of the day for this timeslot
	 */
	public Time getEndTime() {
		return endTime;
	}

	
	/**
	 * @return the ScheduleRule that created this timeslot, or null if it wasn't created from any rule
	 */
	public ScheduleRule getOriginatingRule() {
		return originatingRule;
	}

	/**
	 * @param originatingRule the ScheduleRule that created this timeslot
	 */
	public void setOriginatingRule(ScheduleRule originatingRule) {
		this.originatingRule = originatingRule;
	}
	
	public int compareTo(Object other) {
		final int BEFORE = -1;
	    final int EQUAL = 0;
	    final int AFTER = 1;
		Timeslot otherTimeslot = (Timeslot) other;
		
		if (this.startTime.before(otherTimeslot.getStartTime())) {
			return BEFORE;
		} else if (this.startTime.after(otherTimeslot.getStartTime())) {
			return AFTER;
		}
		
		return EQUAL;
	}
	
	/**
	 * Determines if a particular hour/minute combo falls within this timeslot
	 * 
	 * @param hour
	 * @param minute
	 * @return true if timeslot contains hour and minute 
	 */
	public boolean containsTime(int hour, int minute) {
		Time compareTime = new Time(hour, minute);
		if (compareTime.after(this.startTime) && compareTime.before(this.endTime)) {
			return true;
		}
		if (compareTime.equals(this.startTime) || compareTime.equals(this.endTime)) {
			return true;
		}
		return false;
		
//		if (hour >= this.startHour && hour <= this.endHour) {
//			if (hour == this.startHour) {
//				return (minute >= this.startMinute);
//			} else if (hour == this.endHour) {
//				return (minute <= this.endMinute);
//			} else {
//				return true;
//			}
//		}
//		return false;
	}
	
	/**
	 * Determines if the time specified in a calendar falls within this timeslot
	 * 
	 * @param cal
	 * @return true if timeslot contains the time specified in this calendar
	 */
	public boolean containsTime(Calendar cal) {
		return containsTime(cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE));
	}
	
	public boolean containsTime(Date time) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(time);
		return containsTime(cal);
	}
	
	
	/**
	 * For help with calendar display: Return the count of minute increments that this timeslot spans
	 * (ie a timeslot of 9:00 - 10:30 has 6 15-minute increments)
	 * 
	 * @param increment
	 * @return increment count
	 */
	public int getIncrementCount(int increment) {
		
		int count = 0;
		Calendar startCal = this.startTime.toCalendar();
		Calendar endCal = this.endTime.toCalendar();
		
		while (!startCal.getTime().after(endCal.getTime())) {
			startCal.add(Calendar.MINUTE, increment);
			count++;
		}
		return count;
	}
	
	
	/**
	 * @return the number of 15 minute increments that this timeslot spans
	 */
	public int getQuarterHourIncrementCount() {
		return this.getIncrementCount(15);
	}

	/**
	 * Return true if either startTime or endTime fall within the range of compareStartTime and compareEndTime 
	 * and vice versa
	 */
	public boolean overlapsWith(Timeslot otherTimeslot) {
		if (startTime.isBetween(otherTimeslot.getStartTime(), otherTimeslot.getEndTime()) ||
			endTime.isBetween(otherTimeslot.getStartTime(), otherTimeslot.getEndTime()) ||
			otherTimeslot.getStartTime().isBetween(startTime, endTime) ||
			otherTimeslot.getEndTime().isBetween(startTime, endTime) ||
			startTime.equals(otherTimeslot.getStartTime()) ||
			endTime.equals(otherTimeslot.getEndTime())) {
			
				return true;
			}
			
			return false;
		
	}

	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append(this.getStartTime());
		sb.append("-");
		sb.append(this.getEndTime());
		sb.append(" ");
		sb.append(this.isAvailable() ? "on" : "off");
		return sb.toString();
	}

}